package app.services;

import app.Const;
import app.constant.DictConstant;
import app.constant.TransferConstant;
import app.kit.TypeKit;
import app.models.member.MemberProduct;
import app.models.order.TradeMoney;
import app.models.product.Brand;
import app.models.product.Product;
import app.models.transfer.TransferProduct;
import app.services.profit.ProfitService;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import goja.Logger;
import goja.StringPool;
import goja.lang.Lang;
import goja.plugins.sqlinxml.SqlKit;
import org.joda.time.DateTime;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

import static app.Const.FIELD_AMOUNT;
import static app.Const.FIELD_MEMBER;
import static app.Const.FIELD_ORDER_ID;
import static app.Const.FIELD_PRICE;
import static app.Const.FIELD_STATUS;
import static app.constant.MemberConstant.PRODUCT_EXPIRE;
import static app.constant.MemberConstant.PRODUCT_FOUND;
import static app.constant.MemberConstant.PRODUCT_SALES_SUCCESS;
import static app.constant.ProductConstant.EMPTY;
import static app.constant.ProductConstant.END;
import static app.constant.ProductConstant.END_SALES;
import static app.constant.ProductConstant.FOUND;
import static app.constant.ProductConstant.ONLINE;
import static goja.StringPool.PK_COLUMN;

/**
 * <p> </p>
 *
 * @author sogYF
 * @version 1.0
 * @since JDK 1.6
 */
public final class ProductService  {

    public static final String SQL_UPDATEMEMBERPRODUCTSTATUS = "memberproduct.updateProductStatus";

    private ProductService() {
    }

    public static final ProductService me = new ProductService();

    /**
     * 产品状态检查
     * @param time 时间
     */
    public void statusCheck(DateTime time) {

        // 取得三类产品
        // 1. 销售中的产品； 判断是否已经销售期结束，如果销售期结束 如果金额满足，表示售罄；否则表示销售期结束
        // 2. 售罄的产品； 判断是否已到起息日，如果已经到起息日，则判断 产品状态为 已成立；
        // 3. 已成立的产品； 判断是否到期，如果产品已到期，则设置产品状态为已结束
        final List<Product> products = Product.dao.findByCheckStatus(time);

        for (final Product product : products) {
            // 产品状态
            final int status = TypeKit.getStatus(product);
            switch (status) {
                case ONLINE:
                    onlineProductCheck(product, time);
                    break;
                case END_SALES:
                case EMPTY:
                    //售罄或者销售期结束
                    emptyProductCheck(product, time);
                    break;
                case FOUND:
                    foundProductCheck(product, time);
                    break;
            }

        }
    }


    public void boardstat(){
        List<Brand> brands = Brand.dao.findAll();

        for (Brand brand : brands) {
            //统计产品平均收益率
            int brandId = TypeKit.getInt(brand, StringPool.PK_COLUMN);
            double yield = Product.dao.avgYieldByBrand(brandId);
            int buyers = Product.dao.buyersByBrand(brandId);
            double amount = Product.dao.amountByBrand(brandId);

            brand.set("avg_yield", yield);
            brand.set("persons", buyers);
            brand.set(Const.FIELD_AMOUNT, amount);

            boolean ok = brand.update();
            Logger.info(" Product Board stat is {}!", ok ? "invoke ok" : "invoke error");
        }
    }

    /**
     * 产品起息成立状态处理
     *
     * @param product 产品
     * @param time    当前时间
     * @return 是否操作成功
     */
    private boolean foundProductCheck(final Product product, DateTime time) {


        final int productId = TypeKit.getInt(product, PK_COLUMN);
        // 到期时间
        DateTime due_date = TypeKit.getDateTime(product, "due_date");
        if (due_date == null) {
            Logger.error("产品到期时间不存在，无法进行产品状态的处理!");
            return false;
        }
        if (due_date.getYear() == time.getYear()
                && due_date.getMonthOfYear() == time.getMonthOfYear()
                && due_date.getDayOfMonth() <= time.getDayOfMonth()) {
            // 会员产品状态： K 已结束 - 不可赎回 不可转让
            final int memberProductStatus = PRODUCT_EXPIRE;
            // 已结束
            product.set(FIELD_STATUS, END);


            boolean ok = Db.tx(new IAtom() {
                @Override
                public boolean run() throws SQLException {
                    int records = Db.update(SqlKit.sql(SQL_UPDATEMEMBERPRODUCTSTATUS), memberProductStatus, productId);
                    // 同时设置转让产品失效
                    return product.update() && records >= 0 && TransferProduct.dao.updateStatusByProduct(productId, TransferConstant.STATUE_FAIL);
                }
            });
            if (ok) {
                //计算会员收益
               invokeProfit(productId);
            }
        }
        return false;
    }

    /**
     * 某个产品收益计算
     * @param productId 产品信息
     */
    public void invokeProfit(int productId) {
        Logger.info("  Started calculating yield to maturity...");

//        int page = 1;
        List<MemberProduct> memberProducts;
//        boolean run = true;
//        while (run) {
            // 1. 查询会员的未结束的理财产品
            memberProducts = MemberProduct.dao.findByProductProfit(DictConstant.PROFIT_ONCE, productId);

//            run = !Lang.isEmpty(memberProducts);

//            if (run) {
                // 2. 计算收益信息
                for (MemberProduct memberProduct : memberProducts) {
                    ProfitService.me.onceTimeCollection(memberProduct);
                }
//            }
//            page++;
//        }
        Logger.info("ended calculating yield to maturity...");
    }


    /**
     * 售罄产品状态处理
     *
     * @param product 产品
     * @param time    时间
     * @return 是否操作成功
     */
    private boolean emptyProductCheck(final Product product, DateTime time) {
        DateTime valuedate = TypeKit.getDateTime(product, "valuedate");
        if (valuedate == null) {
            Logger.error("产品起息日期错误，无法进行在线产品状态的处理!");
            return false;
        }
        final int productId = TypeKit.getInt(product, PK_COLUMN);
        // 售罄

        // 产品起息日期是否为今天，如果为今天，则判断产品为已成立，对会员产品进行成立状态处理
        int year = time.getYear(), monthOfYear = time.getMonthOfYear(), dayOfMonth = time.getDayOfMonth();
        if (valuedate.getYear() == year
                && valuedate.getMonthOfYear() == monthOfYear
                && valuedate.getDayOfMonth() <= dayOfMonth) {
            // 会员产品状态：已成立
            final int memberProductStatus = PRODUCT_FOUND;
            // 已成立
            product.set(FIELD_STATUS, FOUND);
            /**
             * 自动成立 进度自动升为100%
             */
            product.set("progress", 100);

            final TradeMoney tradeMoney = TradeMoney.raisedSuccess(productId, product.getBigDecimal(FIELD_PRICE));
            return Db.tx(new IAtom() {
                @Override
                public boolean run() throws SQLException {
                    int records = Db.update(SqlKit.sql(SQL_UPDATEMEMBERPRODUCTSTATUS), memberProductStatus, productId);
                    return product.update() && tradeMoney.save() &&  records >= 0;
                }
            });
        }
        return false;
    }

    /**
     * 在线销售的产品状态处理
     * @param product 产品
     * @param time 时间
     * @return 是否操作成功
     */
    private boolean onlineProductCheck(final Product product, DateTime time) {

        // 销售截至日期
        DateTime end_date = TypeKit.getDateTime(product, "end_date");
        if (end_date == null) {
            Logger.error("产品销售期不存在，无法进行在线产品状态的处理!");
            return false;
        }
        final int productId = TypeKit.getInt(product, PK_COLUMN);
        // 销售截至日期是否为今天，如果为今天，则判断产品为销售结束，对会员产品进行销售处理
        int year = time.getYear(), monthOfYear = time.getMonthOfYear(), dayOfMonth = time.getDayOfMonth();
        if (end_date.getYear() == year
                && end_date.getMonthOfYear() == monthOfYear
                && end_date.getDayOfMonth() <= dayOfMonth) {
            final int memberProductStatus;
            // 如果可投金额大于0（可投金额的计算在支付回调处理上）
            if (TypeKit.getDouble(product, "remaining_amount") > 0) {
                // 产品销售结束
                product.set(FIELD_STATUS, END_SALES);
                return product.update();

            } else {
                // 售罄
                product.set(FIELD_STATUS, EMPTY);
                // 处理会员数据
                memberProductStatus = PRODUCT_SALES_SUCCESS;

                return Db.tx(new IAtom() {
                    @Override
                    public boolean run() throws SQLException {
                        int records = Db.update(SqlKit.sql(SQL_UPDATEMEMBERPRODUCTSTATUS), memberProductStatus, productId);
                        return product.update() && records >= 0;
                    }
                });
            }
        }
        return false;
    }

    /**
     * 批处理募集失败的打款纪录
     *
     * @param productId 产品
     */
    public void generateFailMoney(int productId) {
        boolean data_has_next = true;
        int page = 1;
        final DateTime exec_time = DateTime.now();
        while (data_has_next) {
            List<MemberProduct> memberProducts = MemberProduct.dao.findByProductWithPage(productId, page, 1000);
            data_has_next = !Lang.isEmpty(memberProducts);
            if (data_has_next) {
                Object[][] params = new Object[memberProducts.size()][];
                Object[] param;
                MemberProduct memberProduct;
                for (int i = 0; i < memberProducts.size(); i++) {
                    memberProduct = memberProducts.get(i);
                    param = new Object[11];
                    param[0] = memberProduct.getNumber(FIELD_MEMBER);
                    param[1] = memberProduct.getNumber(PK_COLUMN);
                    param[2] = productId;
                    param[3] = memberProduct.getNumber(FIELD_AMOUNT);
                    param[4] = TradeMoney.FAIL_TYPE;
                    param[5] = new Timestamp(exec_time.getMillis());
                    param[6] = exec_time.getYear();
                    param[7] = exec_time.getMonthOfYear();
                    param[8] = exec_time.getDayOfMonth();
                    param[9] = TradeMoney.WAIT_STATUS;
                    param[10] = TypeKit.getInt(memberProduct, FIELD_ORDER_ID);
                    params[i] = param;
                }
                Db.batch(SqlKit.sql("trademoney.productfailrecord"), params, 1000);
            }
            page++;
        }
    }
}
